<?php

namespace Biz\Services\Passport;

use Illuminate\Http\Request;
use Biz\Models\Passport\Client;
use Lumen\Security\App\AppIdSecurity;
use Lumen\Security\App\AppSecretSecurity;
use Lumen\Core\Exceptions\BusinessException;
use Biz\Repositories\Passport\ClientRepository;
use Laravel\Passport\ClientRepository as PassportClientRepository;

/**
 * ClientRepository.
 *
 * @license [http://www.85do.com] [杭州永奥网络科技有限公司]
 * @copyright Copyright (c) 2018-2026 Hangzhou Yongao Technology Co., Ltd. All rights reserved.
 */
class ClientService
{
    /**
     * @var \Lumen\Repository\Contracts\RepositoryContract
     */
    protected $repository;

    /**
     * The client repository instance.
     *
     * @var \Laravel\Passport\ClientRepository
     */
    protected $clients;

    /**
     * RepositoryController constructor.
     *
     * @param ClientRepository $repository
     */
    public function __construct(ClientRepository $repository, PassportClientRepository $clients)
    {
        $this->repository = $repository;
        $this->clients    = $clients;
    }

    /**
     * Find that client.
     *
     * @param int $id
     *
     * @throws BusinessException
     *
     * @return Client
     */
    public function find(int $id): Client
    {
        $token = $this->repository->find($id);
        if (is_null($token)) {
            throw new BusinessException(trans('oauth.client_not_found'));
        }

        return $token;
    }

    /**
     * Store a new client.
     *
     * @param \Illuminate\Http\Request $request
     *
     * @return Client
     */
    public function store(Request $request): Client
    {
        $data = $request->all();

        return $this->create($data);
    }

    /**
     * Create a new client.
     *
     * @param array $data
     *
     * @throws BusinessException
     *
     * @return Client
     */
    public function create(array $data): Client
    {
        if (! isset($data['user_id'])) {
            throw new BusinessException('请传入用户ID');
        }

        if (! isset($data['name'])) {
            throw new BusinessException('请传入客户端名称');
        }

        if (! isset($data['redirect'])) {
            throw new BusinessException('请传入客户端回调地址');
        }

        /** @var \Laravel\Passport\Client $passportClientModel */
        $passportClientModel = $this->clients->create(
            $data['user_id'], $data['name'], $data['redirect']
        )->makeVisible('secret');

        // Conversion
        $model = $this->repository->createModel();
        $model->forceFill($passportClientModel->toArray());
        $model->showSecret();

        return $model;
    }

    /**
     * edit client.
     *
     * @param string $id
     * @param array  $data
     *
     * @throws BusinessException
     *
     * @return Client
     */
    public function edit(string $id, array $data): Client
    {
        $id = Client::decodeUid($id);

        return $this->update($id, $data);
    }

    /**
     * Update client.
     *
     * @param int   $id
     * @param array $data
     *
     * @throws BusinessException
     *
     * @return Client
     */
    public function update(int $id, array $data): Client
    {
        $client = $this->clients->find($id);
        if (is_null($client)) {
            throw new BusinessException(trans('oauth.client_not_found'));
        }

        if (! isset($data['name'])) {
            throw new BusinessException('请传入客户端名称');
        }

        if (! isset($data['redirect'])) {
            throw new BusinessException('请传入客户端回调地址');
        }

        /** @var \Laravel\Passport\Client $passportClientModel */
        $passportClientModel = $this->clients->update($client, $data['name'], $data['redirect']);

        // Conversion
        $model = $this->repository->createModel();
        $model->forceFill($passportClientModel->toArray());

        return $model;
    }

    /**
     * Delete client.
     *
     * @param string $id
     *
     * @throws \Exception
     *
     * @return bool
     */
    public function remove(string $id): bool
    {
        $id = Client::decodeUid($id);

        return $this->delete($id);
    }

    /**
     * Delete client.
     *
     * @param int $id
     *
     * @throws \Exception
     *
     * @return bool
     */
    public function delete(int $id): bool
    {
        $client = $this->clients->find($id);
        if (is_null($client)) {
            throw new BusinessException(trans('oauth.client_not_found'));
        }

        $this->clients->delete($client);

        return true;
    }

    /**
     * Get OAuth Client.
     *
     * @param string $appId
     * @param string $appSecret
     *
     * @throws BusinessException
     *
     * @return Client
     */
    public function getClientByAppIdAndAppSecret(string $appId, string $appSecret): Client
    {
        // Decode
        $appIdSecurity = new AppIdSecurity();
        $appId         = $appIdSecurity->decode($appId);
        if (empty($appId)) {
            throw new BusinessException(trans('oauth.invalid_argument'));
        }

        // Get OAuth Client
        $oauthClient = $this->find(intval($appId));

        $appSecretSecurity = new AppSecretSecurity($oauthClient->secret);

        $appSecret = $appSecretSecurity->decode($appSecret);

        if ($appId !== $appSecret) {
            throw new BusinessException(trans('oauth.invalid_argument'));
        }

        return $oauthClient;
    }
}
